package com.sd365.permission.centre.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.sd365.common.core.annotation.mybatis.Pagination;
import com.sd365.common.core.annotation.stuffer.CommonFieldStuffer;
import com.sd365.common.core.annotation.stuffer.IdGenerator;
import com.sd365.common.core.annotation.stuffer.MethodTypeEnum;
import com.sd365.common.core.common.advice.MyPageInfo;
import com.sd365.common.core.common.exception.BusinessException;
import com.sd365.common.core.common.exception.code.BizErrorCode;
import com.sd365.common.core.common.service.AbstractBusinessService;
import com.sd365.common.core.context.BaseContextHolder;
import com.sd365.common.util.BeanUtil;
import com.sd365.permission.centre.dao.mapper.ResourceMapper;
import com.sd365.permission.centre.dao.mapper.RoleMapper;
import com.sd365.permission.centre.dao.mapper.RoleResourceMapper;
import com.sd365.permission.centre.entity.Resource;
import com.sd365.permission.centre.pojo.dto.ResourceDTO;
import com.sd365.permission.centre.pojo.dto.SubSystemDTO;
import com.sd365.permission.centre.pojo.query.ResourceQuery;
import com.sd365.permission.centre.pojo.vo.ResourceVO;
import com.sd365.permission.centre.service.ResourceService;
import com.sd365.permission.centre.service.cache.IResourceCache;
import com.sd365.permission.centre.service.cache.ResourceCache;
import com.sd365.permission.centre.service.config.Global;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.List;
/**
 * @Class ResourceServiceImpl
 * @Description  资源管理服务类，主要实现资源的增删改查，为了提供认证和鉴权模块的执行效率该类
 * 提供了initRedis方法在容器启动的时候进行缓存初始化，该类使用spring cache注解维护缓存
 * @Author Administrator
 * @Date 2023-02-25  8:04
 * @version 1.0.1
 */
@Slf4j
@Service
public class ResourceServiceImpl extends AbstractBusinessService implements ResourceService {
    /**
     * 缓存操作接口
     */
    @Autowired
    private IResourceCache resourceCache;
    /**
     *  资源mapper
     */
    @Autowired
    private ResourceMapper resourceMapper;
    /**
     *  基础框架中的id生成器
     */
    @Autowired
    private IdGenerator idGenerator;
    /**
     *  redis操作模板
     */
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     *  对应操作 basic_role_resource表
     */
    @Autowired
    private RoleResourceMapper roleResourceMapper;
    /**
     * 角色mappper
     */
    @Autowired
    private RoleMapper roleMapper;


    @Override
    public List<ResourceDTO> loadResource2Cache(ResourceQuery resourceQuery) {
        List<Resource> resources = resourceMapper.commonQuery(resourceQuery);
        log.debug("resources---------->{}",resources);
        // 加载所有的resource覆盖内存的resource
        for(Resource resource : resources){
            //    Global.RESOURCE_ID_KEY 后续使用 Common的 config模块
            //redisTemplate.opsForValue().set(Global.RESOURCE_ID_KEY+resource.getId(),resource);
            resourceCache.add2Cache(resource);
        }
       return  BeanUtil.copyList(resources,ResourceDTO.class);
    }

    @Pagination
    @CommonFieldStuffer(methodType = MethodTypeEnum.QUERY)
    @Override
    public List<ResourceDTO> commonQuery(ResourceQuery resourceQuery) {

        List<Resource> resources = resourceMapper.commonQuery(resourceQuery);
        setPageInfo2BaseContextHolder((Page)resources);

        if (!CollectionUtils.isEmpty(resources)) {
            Page page = (Page) resources;
            //BaseContextHolder.set("pageInfo", JSON.toJSONString(new MyPageInfo(page.getTotal(), page.getPages())));
            List<ResourceDTO> resourceDTOS = BeanUtil.copyList(resources, ResourceDTO.class, new BeanUtil.CopyCallback() {
                @Override
                public void copy(Object o, Object o1) {
                    Resource resource1 = (Resource) o;
                    ResourceDTO resourceDTO = (ResourceDTO) o1;
                    if (resource1.getResource() != null) {
                        ResourceDTO copy = BeanUtil.copy(resource1.getResource(), ResourceDTO.class);
                        resourceDTO.setResourceDTO(copy);
                    }
                    if (resource1.getSubSystem() != null) {
                        BeanUtil.copy(resource1.getSubSystem(), resourceDTO.getSubSystem(), SubSystemDTO.class);
                    }
                }
            });
            return resourceDTOS;
        } else {
            return new ArrayList<>();
        }

    }



    @Pagination
    @Override
    public List<ResourceDTO> query(ResourceQuery resourceQuery) {
        List<Resource> resources = resourceMapper.commonQuery(resourceQuery);
        Page page = (Page) resources;
        BaseContextHolder.set("pageInfo", JSON.toJSONString(new MyPageInfo(page.getTotal(), page.getPages())));
        return  BeanUtil.copyList(resources, ResourceDTO.class);
    }

    @Override
    public ResourceVO add(ResourceDTO resourceDTO) {
        // TODO 业务检查，检查在同一个子系统菜单不可以重复
        Resource resource = BeanUtil.copy(resourceDTO, Resource.class);
        //调用雪花计算ID
        if (ObjectUtils.isEmpty(resourceDTO.getId())){
            resource.setId(idGenerator.snowflakeId());
        }

        ResourceVO resourceVO= resourceMapper.insert(resource)>0 ? BeanUtil.copy(resource, ResourceVO.class)
              : new ResourceVO();
        // 如果添加成功则同步到缓存
        if(resourceVO.getId()>0){
            resourceCache.add2Cache(resource);
        }
        return resourceVO;
    }

    @Override
    @CommonFieldStuffer(methodType = MethodTypeEnum.DELETE)
    public Boolean batchDelete(ResourceDTO[] resourceDTOS) {
        if (ObjectUtils.isEmpty(resourceDTOS)) {
            throw new BusinessException(BizErrorCode.PARAM_VALID_FIELD_REQUIRE, new Exception("batchDelete 方法错误"));
    }
        for (ResourceDTO resourceDTO : resourceDTOS) {
            Example example = new Example(Resource.class);
            example.createCriteria().andEqualTo("id", resourceDTO.getId());
            if (resourceMapper.deleteByExample(example)<= 0) {
                throw new BusinessException(BizErrorCode.DATA_DELETE_FAIL_EXITS_REF_RECORD, new Exception(String.format("删除的记录id %d 没有匹配到版本", resourceDTO.getId())));
            }
            // 同时删除缓存
            resourceCache.deleteCache(resourceDTO.getId());
        }
        return true;
    }

    @Override
    @CommonFieldStuffer(methodType = MethodTypeEnum.DELETE)
    public Boolean remove(Long id) {
        Example example = new Example(Resource.class);
        example.createCriteria().andEqualTo("id", id);
        boolean result=resourceMapper.deleteByExample(example)>0;
        if(result){
        // 手工方式维护cache
            resourceCache.deleteCache(id);
        }
        return result;

    }

    @Override
    public ResourceVO modify(ResourceDTO resourceDTO) {
        Resource resource = BeanUtil.copy(resourceDTO, Resource.class);
        if (resourceDTO.getVersion() != null) {
            Long version = resourceDTO.getVersion();
            resource.setVersion(version++);
        }
        Example example = new Example(Resource.class);
        example.createCriteria().andEqualTo("id", resourceDTO.getId());
        super.baseDataStuff4Updated(resource);
        ResourceVO resourceVO=resourceMapper.updateByExampleSelective(resource, example) > 0
        ? BeanUtil.copy(resource,ResourceVO.class)
        : new ResourceVO();
        if(resourceDTO.getId()>0){
            // 如果更新成功则同步缓存
            resourceCache.updateCache(resource);
        }
        return resourceVO;

    }

    @Override
    public ResourceDTO copy(Long id) {
        /**
         查询 id的客户信息
         修改 id 插入行的客户信息
         */
        Resource resource = resourceMapper.selectByPrimaryKey(id);
        if (resource != null) {
            resource.setId(idGenerator.snowflakeId());
            if (resourceMapper.insert(resource) > 0) {
                ResourceDTO resourceDTO = BeanUtil.copy(resource, ResourceDTO.class);
                return resourceDTO;
            } else {
                throw new BusinessException(BizErrorCode.DATA_INSERT_RETURN_EFFECT_LATTER_ZERO, new Exception("copy 方法错误"));
            }
        } else {
            throw new BusinessException(BizErrorCode.DATA_INSERT_RETURN_EFFECT_LATTER_ZERO, new Exception("INSERT 方法返回0"));
        }
    }

    @Override
    public ResourceDTO queryById(Long id) {

        // 先从缓存取如果没有则从数据库取
        Resource resource =resourceCache.getCacheResourceById(id);
        if(null==resource){
            resource=resourceMapper.findById(id);
        }
        if (null==resource) {
            return new ResourceDTO();
        }else{
            // 资源关联了 父节点以及子系统因此需要进行拷贝赋值
            ResourceDTO resourceDTO = BeanUtil.copy(resource, ResourceDTO.class);
            if (resource.getSubSystem() != null) {
                resourceDTO.setSubSystem(BeanUtil.copy(resource.getSubSystem(), SubSystemDTO.class));
            }else{
                resourceDTO.setSubSystem(new SubSystemDTO());
            }
            if (resource.getResource() != null) {
                resourceDTO.setResourceDTO(BeanUtil.copy(resource.getResource(), ResourceDTO.class));
            }else{
                resourceDTO.setResourceDTO(new ResourceDTO());
            }
            return resourceDTO;
        }
    }

    @Override
    public ResourceDTO findByParentId(Long id) {
        return BeanUtil.copy(resourceMapper.findByParentId(id), ResourceDTO.class);
    }

    @Override
    public List<ResourceDTO> queryResourceByMenu() {
        Example example = new Example(Resource.class);
        example.createCriteria().andEqualTo("resourceType", (byte) 0);
        List<Resource> resources = resourceMapper.selectByExample(example);
        return BeanUtil.copyList(resources, ResourceDTO.class);

    }
}
